Path為SwiftUI的畫線元件,通常可以用來畫曲線圖,或者其它圖形,一個最基本的Path使用方法:
Path { path in
path.move(to: CGPoint(x: 50, y: 300))
path.addLine(to: CGPoint(x: 300, y: 300))
}
.stroke(.blue, style: StrokeStyle(lineWidth: 2))
path.move表示設定線的起始點,path.addLine表示設定線的終點,所以這裡就表示畫出一條線,從位置(50, 300)到(300, 300),顯示如圖:
加入GeometryReader來根據螢幕的寬度調整,例如:
GeometryReader { geometry in
let startPoint: CGFloat = 50
Path { path in
path.move(to: CGPoint(x: startPoint, y: 300))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: 300))
}
.stroke(.blue, style: StrokeStyle(lineWidth: 2))
}
這裡我將前後距離根據螢幕寬度留白50,顯示如圖:
繼續使用path.addLine畫出一個矩形出來,例如:
Path { path in
path.move(to: CGPoint(x: startPoint, y: 300))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: 300))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: 500))
path.addLine(to: CGPoint(x: startPoint, y: 500))
path.addLine(to: CGPoint(x: startPoint, y: 300))
}
.stroke(.blue, style: StrokeStyle(lineWidth: 2))
顯示如圖:
使用迴圈重複畫出虛線出來,例如:
Path { path in
for i in 1..<4 {
let y = CGFloat(300 + i * 50)
path.move(to: CGPoint(x: startPoint, y: y))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: y))
}
}
.stroke(.blue, style: StrokeStyle(lineWidth: 1, dash: [2, 2]))
在這裡畫出3條虛線,每一個虛線都間隔50。
顯示如圖:
接下來宣告一個陣列用來畫出折線圖的資料,例如:
let datas: [CGFloat] = [10, 20, 35, 40, 0]
然後計算出這個線圖的範圍:
let chartWidth = geometry.size.width - startPoint * 2
根據螢幕的寬度與前後兩邊留白,算出圖只能畫在這個寬度內。
接下每一個點的x軸位置,必須要能夠根據datas的陣列內容來計算出來:
let xSpace = chartWidth / CGFloat(datas.count - 1)
表示陣列有多少個點,就計算出每一個點的距離為多少。
然後用迴圈去走訪陣列datas,計算出x的位置,與y軸位置:
let max = datas.max() ?? 0
for i in 0..<datas.count {
let data = datas[i]
let x = startPoint + CGFloat(i) * xSpace
let y = 500 - (data * 200) / max
if i == 0 {
path.move(to: CGPoint(x: x, y: y))
}
else {
path.addLine(to: CGPoint(x: x, y: y))
}
}
因為整個線圖的y軸位置為300到500之間,所以y這裡的算法會先根據陣列的值算出比例位置之後,在使用500去減掉,畫出來的位置才會由下往上。
最後顯示如圖:
最後完整程式碼:
let datas: [CGFloat] = [10, 20, 35, 40, 0]
var body: some View {
GeometryReader { geometry in
let startPoint: CGFloat = 50
Path { path in
path.move(to: CGPoint(x: startPoint, y: 300))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: 300))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: 500))
path.addLine(to: CGPoint(x: startPoint, y: 500))
path.addLine(to: CGPoint(x: startPoint, y: 300))
}
.stroke(.blue, style: StrokeStyle(lineWidth: 2))
Path { path in
for i in 1..<4 {
let y = CGFloat(300 + i * 50)
path.move(to: CGPoint(x: startPoint, y: y))
path.addLine(to: CGPoint(x: geometry.size.width - startPoint, y: y))
}
}
.stroke(.blue, style: StrokeStyle(lineWidth: 1, dash: [2, 2]))
Path { path in
let chartWidth = geometry.size.width - startPoint * 2
let xSpace = chartWidth / CGFloat(datas.count - 1)
let max = datas.max() ?? 0
for i in 0..<datas.count {
let data = datas[i]
let x = startPoint + CGFloat(i) * xSpace
let y = 500 - (data * 200) / max
if i == 0 {
path.move(to: CGPoint(x: x, y: y))
}
else {
path.addLine(to: CGPoint(x: x, y: y))
}
}
}
.stroke(.red, style: StrokeStyle(lineWidth: 1))
}
}
從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始 Day15 [完]